<%# The license inside this block applies to this file.
# Copyright 2017 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-%>
def updated_record(module):
    return {
        'kind': 'dns#resourceRecordSet',
        'name': module.params['name'],
        'type': module.params['type'],
        'ttl': module.params['ttl'] if module.params['ttl'] else 900,
        'rrdatas': module.params['target']
    }


def unwrap_resource(result, module):
    if not result:
        return None
    return result[0]


class SOAForwardable(object):
    def __init__(self, params, module):
        self.params = params
        self.module = module

    def fail_json(self, *args, **kwargs):
        self.module.fail_json(*args, **kwargs)

    def raise_for_status(self, *args, **kwargs):
        self.module.raise_for_status(*args, **kwargs)


def prefetch_soa_resource(module):

    resource = SOAForwardable({
        'type': 'SOA',
        'managed_zone': module.params['managed_zone'],
        'name': replace_resource_dict(module.params['managed_zone'], 'dnsName'),
        'project': module.params['project'],
        'scopes': module.params['scopes'],
        'service_account_file': module.params.get('service_account_file'),
        'auth_kind': module.params['auth_kind'],
        'service_account_email': module.params.get('service_account_email'),
        'service_account_contents': module.params.get('service_account_contents')
    }, module)

    result = fetch_wrapped_resource(resource, 'dns#resourceRecordSet',
                                    'dns#resourceRecordSetsListResponse',
                                    'rrsets')
    if not result:
        raise ValueError("Google DNS Managed Zone %s not found" %
replace_resource_dict(module.params['managed_zone'], 'name'))
    return result


def create_change(original, updated, module):
    auth = GcpSession(module, 'dns')
    return return_if_change_object(module,
                                   auth.post(collection(module),
                                             resource_to_change_request(
                                                 original, updated, module)
                                             ))


# Fetch current SOA. We need the last SOA so we can increment its serial
def update_soa(module):
    original_soa = prefetch_soa_resource(module)

    # Create a clone of the SOA record so we can update it
    updated_soa = copy.deepcopy(original_soa)

    soa_parts = updated_soa['rrdatas'][0].split(' ')
    soa_parts[2] = str(int(soa_parts[2]) + 1)
    updated_soa['rrdatas'][0] = ' '.join(soa_parts)
    return [original_soa, updated_soa]


def resource_to_change_request(original_record, updated_record, module):
    original_soa, updated_soa = update_soa(module)
    result = new_change_request()
    add_additions(result, updated_soa, updated_record)
    add_deletions(result, original_soa, original_record)
    return result


def add_additions(result, updated_soa, updated_record):
    if updated_soa:
        result['additions'].append(updated_soa)
    if updated_record:
        result['additions'].append(updated_record)


def add_deletions(result, original_soa, original_record):
    if original_soa:
        result['deletions'].append(original_soa)

    if original_record:
        result['deletions'].append(original_record)


# TODO(nelsonjr): Merge and delete this code once async operation
# declared in api.yaml
def wait_for_change_to_complete(change_id, module):
    status = 'pending'
    while status == 'pending':
        status = get_change_status(change_id, module)
        if status != 'done':
            time.sleep(0.5)


def get_change_status(change_id, module):
    auth = GcpSession(module, 'dns')
    link = collection(module) + "/%s" % change_id
    return return_if_change_object(module, auth.get(link))['status']


def new_change_request():
    return {
        'kind': 'dns#change',
        'additions': [],
        'deletions': [],
        'start_time': datetime.datetime.now().isoformat()
    }


def return_if_change_object(module, response):
    # If not found, return nothing.
    if response.status_code == 404:
        return None

    if response.status_code == 204:
        return None

    try:
        response.raise_for_status()
        result = response.json()
    except getattr(json.decoder, 'JSONDecodeError', ValueError) as inst:
        module.fail_json(msg="Invalid JSON response with error: %s" % inst)

    if result['kind'] != 'dns#change':
        module.fail_json(msg="Invalid result: %s" % result['kind'])

    return result
